package io.github.wanggit.antrpc.commons.future;

import io.github.wanggit.antrpc.commons.bean.RpcProtocol;
import io.github.wanggit.antrpc.commons.bean.RpcResponseBean;
import io.github.wanggit.antrpc.commons.codec.serialize.ISerializer;
import io.github.wanggit.antrpc.commons.codec.serialize.SerializerFactory;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class ReadClientFuture {

    private final Lock lock = new ReentrantLock();
    private final Condition done = lock.newCondition();
    private final int timeout;
    private RpcProtocol response;
    private ISerializer serializer;

    ReadClientFuture(ISerializer serializer, int timeoutSeconds) {
        this.serializer = serializer;
        timeout = timeoutSeconds;
    }

    private void clear() {
        response = null;
        serializer = null;
    }

    public RpcResponseBean get() {
        RpcProtocol result = null;
        try {
            lock.lock();
            if (response != null) {
                result = response;
            } else {
                if (!done.await(timeout, TimeUnit.SECONDS)) {
                    if (log.isErrorEnabled()) {
                        log.error("Wait timeout, 10s.");
                    }
                    return null;
                }
                result = response;
            }
            if (null != result) {
                return serializer.deserialize(result.getData(), RpcResponseBean.class);
            }
        } catch (InterruptedException e) {
            if (log.isErrorEnabled()) {
                log.error("get response from future interrupted. ", e);
            }
            Thread.currentThread().interrupt();
            return null;
        } finally {
            lock.unlock();
            clear();
        }
        return null;
    }

    void receive(RpcProtocol data) {
        try {
            lock.lock();
            ISerializer newSerializerByByteCmd =
                    SerializerFactory.getInstance()
                            .getDefaultConfigsSerializerByByteCmd(data.getSerializer());
            // 如果使用协议中的 命令码 不能找到指定的序列化工具，那么就使用默认的
            if (null != newSerializerByByteCmd) {
                serializer = newSerializerByByteCmd;
            }
            response = data;
            done.signal();
        } finally {
            lock.unlock();
        }
    }
}
